package me.magicall.db.springjdbc.dao2;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import me.magicall.coll.CollFactory;
import me.magicall.coll.ElementTransformer;
import me.magicall.db.Condition;
import me.magicall.db.ConditionOperator;
import me.magicall.db.FieldComparator;
import me.magicall.db.dao.CommonDao;
import me.magicall.db.dao2.AbsDaoImpl;
import me.magicall.db.dao2.Query;
import me.magicall.db.util.PageInfo;
import me.magicall.db.util.ReturnKeyAndAffect;
import me.magicall.lang.bean.FieldValueAccessor;
import me.magicall.util.kit.Kits;

/**
 * 一个内存数据库(NoSQL)的表。尚无更新操作，只有查询。可用于作为缓存
 * 
 * @author MaGiCalL
 * @param <E> 表的数据,相对于数据库的"记录"
 */
public class Table<E> extends AbsDaoImpl<E> {

	private final FieldValueAccessor<E> fieldValueAccessor;
	private List<E> datas;

	public Table(final FieldValueAccessor<E> fieldValueAccessor, final List<E> datas) {
		super(new CommonDaoImplForTable<E>());
		((CommonDaoImplForTable<E>) commonDao).table = this;
		this.fieldValueAccessor = fieldValueAccessor;
		this.datas = datas;
	}

	public Table(final FieldValueAccessor<E> fieldValueGetter) {
		this(fieldValueGetter, new ArrayList<E>());
	}

	public void setDatas(final List<? extends E> datas) {
		final List<E> list = new ArrayList<E>(datas);
		this.datas = list;
	}

	/**
	 * 获取一个
	 * 
	 * @param config
	 * @return
	 */
	@Override
	public E getOne(Query<E> config) {
		if (config == null) {
			config = new Query<E>();
		}
		config.setPageInfo(PageInfo.FIRST_ONE);
		final List<E> list = list(config);
		return Kits.LIST.isEmpty(list) ? null : list.get(0);
	}

	/**
	 * 获取所有
	 * 
	 * @param modelName
	 * @return
	 */
	@Override
	public List<E> all() {
		final List<E> list = datas;
		return new ArrayList<E>(list);
	}

	/**
	 * 获取列表
	 * 
	 * @param query
	 * @return
	 */
	public List<E> list(final Query<E> query) {
		final List<E> rt = filtModel(query);
		if (Kits.LIST.isEmpty(rt)) {
			return rt;
		}

		return sortAndPaged(query, rt);
	}

	/**
	 * 根据查询条件统计符合条件的数据的数量。
	 * 注：查询中的排序器、分页器不会被使用。
	 * 
	 * @param query
	 * @return
	 */
	public int count(final Query<E> query) {
		return Kits.LIST.checkToEmptyValue(filtModel(query)).size();
	}

	/**
	 * 筛选数据。
	 * 
	 * @param query 查询
	 * @return
	 */
	protected List<E> filtModel(final Query<E> query) {
		final List<E> table = datas;//表里所有的数据
		if (Kits.COLL.isEmpty(table)) {
			//TODO 空表
			return null;
		}

		if (query == null) {
			return table;
		}
		final List<Condition> conditions = query.getConditions();
		if (Kits.LIST.isEmpty(conditions)) {//没有条件,返回全部
			return new ArrayList<E>(table);
		}

		final List<E> rt = new LinkedList<E>();

		//筛选
		final Iterator<Condition> conditionIterator = conditions.iterator();
		{//第一个条件,用来填充rt
			final Condition firstCondition = conditionIterator.next();
			final String fieldName = firstCondition.getFieldName();
			final List<?> refedValues = firstCondition.getRefedValues();
			final ConditionOperator conditionOperator = firstCondition.getConditionOperator();
			for (final E oneModel : table) {
				if (conditionOperator.accept(fieldValueAccessor.getValue(oneModel, fieldName), refedValues)) {
					//如果数据的fieldName字段的值符合refedValues指定的条件,则添加到初次筛选结果中去
					rt.add(oneModel);
				}
			}
		}

		//后面的条件,从rt中删除不合适的
		while (conditionIterator.hasNext()) {
			final Condition condition = conditionIterator.next();
			final String fieldName = condition.getFieldName();
			final List<?> refedValues = condition.getRefedValues();
			final ConditionOperator conditionOperator = condition.getConditionOperator();
			final Iterator<E> rtIterator = rt.iterator();
			while (rtIterator.hasNext()) {
				final E oneModel = rtIterator.next();
				if (!conditionOperator.accept(fieldValueAccessor.getValue(oneModel, fieldName), refedValues)) {
					//如果数据的fieldName字段的值不符合条件refedValues指定的条件,则从初次筛选结果中移除.
					rtIterator.remove();
				}
			}
		}
		return rt;
	}

	/**
	 * 排序和分页。会验证是否存在排序器和分页器。
	 * 
	 * @param query
	 * @param rt
	 * @return
	 */
	protected List<E> sortAndPaged(final Query<E> query, final List<E> rt) {
		final PageInfo pageInfo = query.getPageInfo();
		if (pageInfo == null) {
			sort(query, rt);
			return rt;
		}

		final int offset = pageInfo.getOffset();
		final int rtSize = rt.size();
		if (offset > rtSize) {
			return Kits.LIST.emptyValue();
		}

		//排序
		sort(query, rt);

		//分页
		return Kits.LIST.subList(rt, offset, Math.min(offset + pageInfo.getSize(), rtSize));
	}

	/**
	 * 排序。若未指定排序器，则不会改变集合中数据顺序；否则在排序过程中可能会改变集合的数据顺序。
	 * 
	 * @param query
	 * @param rt
	 */
	protected void sort(final Query<E> query, final List<E> rt) {
		final FieldComparator<? super E> comparator = query.getFieldComparator();
		if (comparator != null) {
			Collections.sort(rt, comparator);
		}
	}

	@Override
	public int del(final Query<E> query) {
		return 0;
	}

	@Override
	public int delById(final Collection<? extends Object> id) {
		return 0;
	}

	protected static class CommonDaoImplForTable<T> implements CommonDao<T> {

		protected Table<T> table;

		@Override
		public T fill(final T modelWithId) {
			final Object id = table.fieldValueAccessor.getValue(modelWithId, table.idFieldName());
			return table.getById(id);
		}

		@Override
		public Collection<T> fill(final T... modelWithId) {
			return fill(CollFactory.L.asList(modelWithId));
		}

		@Override
		public Collection<T> fill(final Collection<T> modelsWithId) {
			final Query<T> query = new Query<T>();
			final Collection<Object> ids = Kits.COLL.transform(modelsWithId, new ElementTransformer<T, Object>() {
				@Override
				public Object transform(final int index, final T element) {
					return table.fieldValueAccessor.getValue(element, table.idFieldName());
				}
			});
			query.addConditions(new Condition(table.idFieldName(), ids));
			return table.list(query);
		}

		@Override
		public ReturnKeyAndAffect addReturnKey(final T model) {
			return new ReturnKeyAndAffect(null, 0);
		}

		@Override
		public ReturnKeyAndAffect addReturnKey(final T... models) {
			return new ReturnKeyAndAffect(null, 0);
		}

		@Override
		public ReturnKeyAndAffect addReturnKey(final Collection<? extends T> models) {
			return new ReturnKeyAndAffect(null, 0);
		}

		@Override
		public int addIfAbsent(final T... models) {
			return 0;
		}

		@Override
		public int addIfAbsent(final Collection<? extends T> models) {
			return 0;
		}

		@Override
		public boolean add(final T model) {
			return false;
		}

		@Override
		public int[] add(final T... models) {
			return Kits.INT.emptyPrimitiveArray();
		}

		@Override
		public int[] add(final Collection<? extends T> models) {
			return Kits.INT.emptyPrimitiveArray();
		}

		@Override
		public int update(final T model) {
			return 0;
		}

		@Override
		public int[] update(final T... models) {
			return Kits.INT.emptyPrimitiveArray();
		}

		@Override
		public int[] update(final Collection<? extends T> models) {
			return Kits.INT.emptyPrimitiveArray();
		}

		@Override
		public boolean addOrUpdate(final T model) {
			return false;
		}

		@Override
		public int[] addOrUpdate(final T... models) {
			return Kits.INT.emptyPrimitiveArray();
		}

		@Override
		public int[] addOrUpdate(final Collection<? extends T> models) {
			return Kits.INT.emptyPrimitiveArray();
		}

		@Override
		public int del(final T model) {
			return 0;
		}

		@Override
		public int[] del(final Collection<? extends T> models) {
			return Kits.INT.emptyPrimitiveArray();
		}

		@Override
		public int[] del(final T... models) {
			return Kits.INT.emptyPrimitiveArray();
		}
	}

	protected FieldValueAccessor<E> getFieldValueAccessor() {
		return fieldValueAccessor;
	}

}
